#!/usr/bin/env bash
#

function usage()
{
	echo -e "A tool to show numastat difference."
	echo -e
	echo -e "usage: $0 [OPTIONS]"
	echo -e
	echo -e "OPTIONS:"
	echo -e "\t-h, print this usage and exit"
	echo -e "\t-p <PID>, to show process info"
	echo -e "\t-i <secs>, seconds between each report"
	echo -e "\t-c <count>, the number of reports generated"
	echo -e
}

# parse arguments
while [[ -n "$1" ]]; do
	# if $1 is last argument, set arg=--, otherwise set arg=$2
	arg=${2:---}
	case "$1" in
	"-p")
		if [[ $arg == -* ]]; then
			echo -e "missing option $1 argument\n"
			usage
			exit -1
		else
			ARG_p=$arg
			shift 2
		fi
		;;
	"-i")
		if [[ $arg =~ ^[0-9]+\.?[0-9]*$ || $arg =~ ^\.[0-9]+$ ]]; then
			ARG_i=$arg
			shift 2
		else
			echo -e "missing option $1 argument\n"
			usage
			exit -1
		fi
		;;
	"-c")
		if [[ $arg =~ ^-?[0-9]+$ ]]; then
			ARG_c=$arg
			shift 2
		else
			echo -e "missing option $1 argument\n"
			usage
			exit -1
		fi
		;;
	"-h")
		usage
		exit 0
		;;
	"--")
		shift
		break
		;;
	*)
		echo -e "unknown option: $1\n"
		usage
		exit -1
		;;
	esac
done

NUMASTAT_CMD="numastat -n${ARG_p:+ -p ${ARG_p}}"
STAT_VALUES=$($NUMASTAT_CMD)

KEYS=("Numa_Hit" "Numa_Miss" "Numa_Foreign" \
      "Interleave_Hit" "Local_Node" "Other_Node")

declare -A STAT_MAP
for k in ${KEYS[*]}; do
	STAT_MAP["${k}"]=$(echo "${STAT_VALUES}" | grep "^${k}")
done

NODE_COUNT=$(expr $(echo ${STAT_MAP["${KEYS[0]}"]} | wc -w) - 2)
COLUMN_WIDTH=15

print_header_line()
{
	printf "%${COLUMN_WIDTH}s" ""
	for ((i = 0; i < ${NODE_COUNT}; i++)); do
		column_name=$(printf "Node %d" $i)
		printf "%${COLUMN_WIDTH}s" "$column_name"
	done
	printf "%${COLUMN_WIDTH}s\n" "Total"

	line=$(printf "%.s-" {1..14})
	printf "%${COLUMN_WIDTH}s" ""
	for ((i = 0; i < ${NODE_COUNT} + 1; i++)); do
		printf "%${COLUMN_WIDTH}s" "$line"
	done
	printf "\n"
}

print_delta()
{
	last=(${STAT_MAP["${1}"]})
	values=$(echo "${STAT_VALUES}" | grep "^${1}")
	current=($values)

	printf "%-${COLUMN_WIDTH}s" "${1}"
	for ((i = 1; i <= ${NODE_COUNT} + 1; i++)); do
		delta=$(echo "${current[$i]} - ${last[$i]}" | bc)
		printf "%${COLUMN_WIDTH}.2f" $delta
	done
	printf "\n"
	STAT_MAP["${1}"]=${values}
}

HEADER_LINE="$(print_header_line)"
SPLIT_LINE1="$(printf "%.s-" {1..80})"
SPLIT_LINE2="$(printf "%.s-" {1..40})"
date
echo "${STAT_VALUES}"
WAIT=${ARG_i:-1}
LOOP=${ARG_c:--1}
for ((t = ${LOOP}; t != 0; t--)); do
	sleep ${WAIT}
	STAT_VALUES=$($NUMASTAT_CMD)
	echo ${SPLIT_LINE1}
	date
	echo "${STAT_VALUES}"
	echo ${SPLIT_LINE2}
	printf "\nPer-node numastat difference (after ${WAIT} seconds):\n"
	echo "${HEADER_LINE}"
	for k in ${KEYS[*]}; do
		print_delta "${k}"
	done
done
